package GUI.calendar;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.HashMap;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.event.ListDataListener;

/**
 * @author mramsey3
 * 
 */
public class CalendarPanel extends JPanel implements ActionListener {

    private static final long serialVersionUID = 1L;
    private static final Color OFFICE_BLUE = new Color(40, 100, 220);
    private static final Color BACKGROUND = Color.WHITE;

    private static HashMap<Integer, String> MONTH_MAP;

    private JPanel northPanel;
    private JLabel monthLabel;
    private JPanel monthNavPanel;
    private JPanel yearDropPanel;
    private JComboBox yearComboBox;
    private JPanel monthDropPanel;
    private JComboBox monthComboBox;

    private JPanel centerPanel;
    private CalendarGridPanel calendarGridPanel;

    private int year = 0;
    private int month = 0;

    /**
     * 
     */
    public CalendarPanel() {
	instantiateMonthMap();

	setPreferredSize(new Dimension(600, 400));
	setBackground(Color.WHITE);
	setBorder(BorderFactory.createLineBorder(Color.BLACK, 4));

	setLayout(new BorderLayout());
	add(getNorthPanel(), BorderLayout.NORTH);
	add(getCenterPanel(), BorderLayout.CENTER);
    }

    /**
     * @return
     */
    private JPanel getNorthPanel() {
	if (northPanel == null) {
	    northPanel = new JPanel();
	    northPanel.setLayout(new BorderLayout());
	    northPanel.setPreferredSize(new Dimension(600, 90));
	    northPanel.setBackground(BACKGROUND);

	    JPanel monthPanel = new JPanel();
	    monthPanel.setLayout(new GridBagLayout());
	    monthPanel.setBackground(BACKGROUND);
	    monthLabel = new JLabel("MAY 2011");
	    monthLabel.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 50));
	    monthLabel.setForeground(OFFICE_BLUE);
	    monthPanel.add(monthLabel);

	    northPanel.add(monthPanel, BorderLayout.CENTER);

	    northPanel.add(getMonthNavPanel(), BorderLayout.SOUTH);
	}
	return northPanel;
    }

    /**
     * @return
     */
    private JPanel getMonthNavPanel() {
	if (monthNavPanel == null) {
	    monthNavPanel = new JPanel();
	    monthNavPanel.setLayout(new BorderLayout());

	    JPanel blankPanel = new JPanel();
	    blankPanel.setBackground(BACKGROUND);
	    monthNavPanel.add(blankPanel, BorderLayout.CENTER);
	    monthNavPanel.add(getYearDropPanel(), BorderLayout.WEST);
	    monthNavPanel.add(getMonthDropPanel(), BorderLayout.EAST);
	}
	return monthNavPanel;
    }

    /**
     * @return
     */
    private JPanel getYearDropPanel() {
	if (yearDropPanel == null) {
	    yearDropPanel = new JPanel();
	    yearDropPanel.setLayout(new GridBagLayout());
	    yearDropPanel.setBackground(BACKGROUND);

	    GridBagConstraints gbc0 = new GridBagConstraints();
	    gbc0.gridx = 0;
	    gbc0.gridy = 0;
	    yearDropPanel.add(Box.createHorizontalStrut(5), gbc0);

	    GridBagConstraints gbc1 = new GridBagConstraints();
	    gbc1.gridx = 1;
	    gbc1.gridy = 0;
	    JLabel yearLabel = new JLabel("YEAR  ");
	    yearLabel.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
	    yearDropPanel.add(yearLabel, gbc1);

	    GridBagConstraints gbc2 = new GridBagConstraints();
	    gbc2.gridx = 2;
	    gbc2.gridy = 0;
	    yearDropPanel.add(getYearComboBox(), gbc2);
	}
	return yearDropPanel;
    }

    /**
     * @return
     */
    private JComboBox getYearComboBox() {
	if (yearComboBox == null) {
	    yearComboBox = new JComboBox(new YearComboBoxModel());
	    yearComboBox.addActionListener(this);
	    yearComboBox.setSelectedIndex(0);
	}
	return yearComboBox;
    }

    /**
     * @return
     */
    private JPanel getMonthDropPanel() {
	if (monthDropPanel == null) {
	    monthDropPanel = new JPanel();
	    monthDropPanel.setLayout(new GridBagLayout());
	    monthDropPanel.setBackground(BACKGROUND);

	    GridBagConstraints gbc1 = new GridBagConstraints();
	    gbc1.gridx = 0;
	    gbc1.gridy = 0;
	    JLabel monthLabel = new JLabel("MONTH  ");
	    monthLabel.setFont(new Font(Font.SANS_SERIF, Font.BOLD, 14));
	    monthDropPanel.add(monthLabel, gbc1);

	    GridBagConstraints gbc2 = new GridBagConstraints();
	    gbc2.gridx = 1;
	    gbc2.gridy = 0;
	    monthDropPanel.add(getMonthComboBox(), gbc2);

	    GridBagConstraints gbc0 = new GridBagConstraints();
	    gbc0.gridx = 2;
	    gbc0.gridy = 0;
	    monthDropPanel.add(Box.createHorizontalStrut(5), gbc0);

	}
	return monthDropPanel;
    }

    /**
     * @return
     */
    private JComboBox getMonthComboBox() {
	if (monthComboBox == null) {
	    monthComboBox = new JComboBox(new MonthComboBoxModel());
	    monthComboBox.addActionListener(this);
	}
	return monthComboBox;
    }

    /**
     * @return
     */
    private JPanel getCenterPanel() {
	if (centerPanel == null) {
	    centerPanel = new JPanel() {
		private static final long serialVersionUID = 1L;

		public void paintComponent(Graphics g) {
		    getCalendarGridPanel().setBounds(10, 10, getWidth() - 20,
			    getHeight() - 20);
		}
	    };
	    centerPanel.setBackground(BACKGROUND);
	    centerPanel.setLayout(null);

	    centerPanel.add(getCalendarGridPanel(), BorderLayout.NORTH);
	}
	return centerPanel;
    }

    /**
     * @return
     */
    public CalendarGridPanel getCalendarGridPanel() {
	if (calendarGridPanel == null) {
	    dateChanged();
	}
	return calendarGridPanel;
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * java.awt.event.ActionListener#actionPerformed(java.awt.event.ActionEvent)
     */
    @Override
    public void actionPerformed(ActionEvent evt) {
	if (evt.getSource() == getYearComboBox()) {
	    try {
		year = Integer.parseInt((String) getYearComboBox()
			.getSelectedItem());
	    } catch (NumberFormatException e) {
	    }
	    ;
	    dateChanged();
	} else if (evt.getSource() == getMonthComboBox()) {
	    for (int monthCount : MONTH_MAP.keySet()) {
		if (MONTH_MAP.get(monthCount).equals(
			getMonthComboBox().getSelectedItem())) {
		    month = monthCount;
		    break;
		}
	    }
	    dateChanged();
	}
    }

    /**
     * 
     */
    private void dateChanged() {
	monthLabel.setText(MONTH_MAP.get(month) + " " + year);

	GregorianCalendar date = new GregorianCalendar(year, month, 0);
	int firstDayOfMonth = date.get(Calendar.DAY_OF_WEEK) % 7;
	int daysInMonth = getDaysInMonth(month);

	int globalDayCount = 0;
	for (int yearCount = 2011; yearCount < year; yearCount++) {
	    globalDayCount += (yearCount % 4 == 0 ? 366 : 365);
	}
	for (int monthCount = 0; monthCount < month; monthCount++) {
	    globalDayCount += getDaysInMonth(monthCount);
	}

	if (calendarGridPanel == null) {
	    calendarGridPanel = new CalendarGridPanel(firstDayOfMonth,
		    daysInMonth, globalDayCount);
	} else {
	    calendarGridPanel.reset(firstDayOfMonth, daysInMonth,
		    globalDayCount);
	}
    }

    /**
     * @param month
     * @return
     */
    private int getDaysInMonth(int month) {
	int daysInMonth = 31;
	switch (month) {
	case 1:
	    daysInMonth = (year % 4 == 0 ? 29 : 28);
	    break;
	case 3:
	    daysInMonth = 30;
	    break;
	case 5:
	    daysInMonth = 30;
	    break;
	case 8:
	    daysInMonth = 30;
	    break;
	case 10:
	    daysInMonth = 30;
	    break;
	default:
	    break;
	}
	return daysInMonth;
    }

    /**
	 * 
	 */
    private void instantiateMonthMap() {
	if (MONTH_MAP == null) {
	    MONTH_MAP = new HashMap<Integer, String>();
	    MONTH_MAP.put(0, "January");
	    MONTH_MAP.put(1, "February");
	    MONTH_MAP.put(2, "March");
	    MONTH_MAP.put(3, "April");
	    MONTH_MAP.put(4, "May");
	    MONTH_MAP.put(5, "June");
	    MONTH_MAP.put(6, "July");
	    MONTH_MAP.put(7, "August");
	    MONTH_MAP.put(8, "September");
	    MONTH_MAP.put(9, "October");
	    MONTH_MAP.put(10, "November");
	    MONTH_MAP.put(11, "December");
	}
    }

    /**
     * @author mramsey3
     * 
     */
    private class YearComboBoxModel implements ComboBoxModel {

	private int selectedYear;

	@Override
	public int getSize() {
	    return 30;
	}

	@Override
	public Object getElementAt(int index) {
	    return String.valueOf(2011 + index);
	}

	public void addListDataListener(ListDataListener l) {
	}

	public void removeListDataListener(ListDataListener l) {
	}

	public void setSelectedItem(Object anItem) {
	    try {
		selectedYear = Integer.parseInt((String) (anItem));
	    } catch (NumberFormatException e) {
		e.printStackTrace();
	    }
	}

	public Object getSelectedItem() {
	    return String.valueOf(selectedYear);
	}
    }

    /**
     * @author mramsey3
     * 
     */
    private class MonthComboBoxModel implements ComboBoxModel {

	private int selectedMonth;

	@Override
	public int getSize() {
	    return 12;
	}

	@Override
	public Object getElementAt(int index) {
	    String monthString = MONTH_MAP.get(index);
	    if (monthString == null) {
		monthString = "Invalid Month";
	    }
	    return monthString;
	}

	public void addListDataListener(ListDataListener l) {
	}

	public void removeListDataListener(ListDataListener l) {
	}

	public void setSelectedItem(Object anItem) {
	    for (int month : MONTH_MAP.keySet()) {
		if (MONTH_MAP.get(month).equals(anItem)) {
		    selectedMonth = month;
		    break;
		}
	    }
	}

	public Object getSelectedItem() {
	    return MONTH_MAP.get(selectedMonth);
	}
    }

}
